home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 3 / Gold Medal Software - Volume 3 (Gold Medal) (1994).iso / virus / secdr13a.arj / SECTSR.ASM < prev    next >
Assembly Source File  |  1994-01-29  |  25KB  |  1,158 lines

  1. ; TSR disk encryptor V1.3A
  2.  
  3. DISKDATA STRUC
  4. DDDRV      DB ?       ;PHYSICAL DRIVE (HD)
  5. DRVLET      DB ?       ;DRIVE LETTER
  6. FIRSTCYL  DW ?       ;FIRST CYLINDER TO ENCRYPT
  7. FIRSTHD   DB ?       ;FIRST HEAD TO ENCRYPT
  8. FIRSTSEC  DB ?       ;FIRST SECTOR (BOOT SECTOR)
  9. LASTCYL   DW ?       ;LAST CYLINDER TO ENCRYPT
  10. MAXSEC      DB ?       ;NUMBER OF SECTORS ON DEVICE
  11. MAXHD      DB ?       ;NUMBER OF HEADS ON DEVICE
  12. SECSIZE   DW ?       ;BLOCK SIZE IN BYTES
  13. SERIAL      DW ?       ;DISK SERIAL NUMBER, FOR IV
  14.       DW ?       ;REST OF DISK SERIAL NUMBER
  15. ACTIVE      DB ?       ;CRYPT THIS DISK? FLAG
  16.       DB ?       ;PAD TO EVEN BOUND
  17. DISKDATA ENDS
  18.  
  19. MAXDRV=4       ;MAX HD PARTITIONS IN SAFE MODE EWS
  20.  
  21. ;; .MODEL TINY
  22. ;; .CODE
  23. _TEXT SEGMENT PARA PUBLIC 'CODE'
  24.  ASSUME CS:_TEXT,DS:_TEXT
  25.  ORG 0100h
  26. START:
  27.  MOV AX,0800h
  28.  MOV DL,0F0h
  29.  INT 13h
  30.  MOV DX,OFFSET ALRINS
  31.  CMP AX,0EDCCh ;1.3 Already Installed?
  32.  JE  ERREX1
  33.  CMP AX,0EDCBh ;IS Previous Version ALREADY INSTALLED?
  34.  JNE LOADTSR
  35. ERREX1:
  36.  MOV AH,9
  37.  INT 21h ;PRINT ERROR AND EXIT
  38.  INT 20h
  39. LOADTSR:
  40.  MOV AH,9
  41.  MOV DX,OFFSET FKEY
  42.  INT 21h ;PRINT SIGN-ON
  43.  
  44.  MOV AX,3513h
  45.  INT 21h ;GET INT VECTOR
  46.  MOV WORD PTR[INT_JOUT+1],BX
  47.  MOV WORD PTR[INT_JOUT+3],ES
  48.  MOV WORD PTR REALBIOS,BX
  49.  MOV WORD PTR REALBIOS+2,ES
  50.  
  51.  MOV DX,OFFSET(I13_ENTRY)
  52.  MOV AX,2513h
  53.  INT 21h ;SET NEW INT VECTOR
  54.  
  55.  MOV AX,3100h
  56.  MOV DX,(END_OF_FILE-START)/16+17
  57.  INT 21h ;GO TSR
  58.  ALIGN 16
  59. TSRSTACK: ;OUR STACK GOES HERE
  60.  NOP
  61.  
  62. I13_ENTRY:
  63.  CLI
  64.  MOV WORD PTR CS:STKSEG,SS
  65.  MOV WORD PTR CS:STKOFS,SP
  66.  MOV WORD PTR CS:IV,CS
  67.  MOV SS,WORD PTR CS:IV
  68.  MOV SP,OFFSET TSRSTACK ;SETUP OUR STACK
  69.  STI
  70.  PUSH AX
  71.  PUSH BX
  72.  PUSH CX
  73.  PUSH DX
  74.  PUSH SI
  75.  PUSH DI
  76.  PUSH BP
  77.  PUSH DS
  78.  PUSH ES
  79.  PUSH CS
  80.  POP DS
  81.  
  82. ;DECIDE IF THIS REQUEST NEEDS PROCESSING
  83.  CMP AH,2 ;READ SECTOR
  84.  JE RDORWR
  85.  CMP AH,3 ;WRITE SECTOR
  86.  JE RDORWR
  87.  CMP AH,8 ;REQUEST FOR ADDRESS?
  88.  JNE TONOPROC
  89.  CMP DL,0F0h ;CORRECT DRIVE NUMBER?
  90.  JNE TONOPROC
  91.  MOV BP,SP
  92.  MOV [BP+10],OFFSET LOADDATA ;DX=DATA ADDRESS
  93.  MOV [BP+12],CS ;CX=CODE SEGMENT
  94.  MOV AX,0EDCCh; ;THIS MEANS V 1.3+ INSTALLED (V1.2- = EDCB)
  95.  JMP RETPROG
  96.  
  97. TONOPROC:
  98.  JMP NOPROC
  99. RDORWR:
  100.  MOV BYTE PTR RQTYPE,AH ;STORE REQUEST TYPE
  101.  MOV BYTE PTR NUMSEC,AL ;STORE NUMBER OF SECTORS
  102.  MOV BYTE PTR STSEC,CL    ;STORE SECTOR; MUST BE MASKED
  103.  AND BYTE PTR STSEC,00111111b ;MASK OFF HIGH 2 BITS
  104.  MOV WORD PTR CALLCX,CX ;KEEP CX FOR DISK ACCESS
  105.  MOV AH,CL        ;WE NEED TO...
  106.  MOV AL,CH        ;SWAP THESE
  107.  MOV CL,6        ;ROTATE 6 BITS...
  108.  SHR AH,CL        ;TO THE RIGHT, NOW AX CONTAINS CYLINDER
  109.  MOV BYTE PTR DRIVE,DL    ;STORE DRIVE
  110.  MOV WORD PTR STCYL,AX    ;STORE CYLINDER
  111.  MOV BYTE PTR STHD,DH    ;STORE HEAD
  112.  MOV WORD PTR BUFOS,BX    ;STORE BUFFER ADDRESS
  113.  MOV WORD PTR BUFSG,ES    ;STORE BUFFER SEGMENT
  114.  
  115.  CMP DL,1           ;FLOPPY DRIVE? EWS
  116.  JBE FLOPPY
  117. ;;; CMP BYTE PTR HDNUM,DL ;IS IT ACTIVE HARD DRIVE?
  118. ;;; JNE NOTHARD
  119.  MOV BP,OFFSET HD1   ;SEARCH DISKDATA BLOCKS
  120.  MOV CX,MAXDRV
  121. SHDLP:
  122.  CMP DL,[BP].DDDRV
  123.  JNE SHDCNT
  124.  CMP AX,[BP].FIRSTCYL
  125.  JB  SHDCNT
  126.  CMP AX,[BP].LASTCYL
  127.  JA  SHDCNT
  128.  CMP [BP].ACTIVE,1    ;ACTIVE HARD DISK PARTITION?
  129.  JE  SHDFND          ;YES
  130.  MOV BYTE PTR BADKEY,1
  131.  JMP BACKFROMBIOS     ;NO. TO RETURN NOT READY
  132. SHDCNT:
  133.  ADD BP,HD2-HD1
  134.  LOOP SHDLP
  135.  JMP NOPROC          ;NOT ACTIVE & NOT SAFE. PASS THRU
  136. SHDFND:
  137.  MOV AX,OFFSET HKEY
  138.  MOV WORD PTR KEY,AX ;SET KEY
  139.  JMP PROCRQ
  140. NOTHARD:
  141. FLOPPY:
  142.  MOV AX,OFFSET FKEY
  143.  MOV WORD PTR KEY,AX ;SET FLOPPY KEY
  144.  CMP DL,0         ;IS IT DRIVE A?
  145.  JNE NOTDRIVEA
  146.  MOV BP,OFFSET FDA   ;SET DISKDATA BLOCK
  147.  JMP PROCRQ
  148. NOTDRIVEA:
  149.  CMP DL,1         ;IS IT DRIVE B?
  150.  JNE NOTDRIVEB
  151.  MOV BP,OFFSET FDB   ;SET DISKDATA BLOCK
  152.  JMP PROCRQ
  153. NOTDRIVEB:
  154. NOPROC2:
  155.  JMP NOPROC
  156.  
  157. PROCRQ: ;RIGHT DRIVE
  158.  
  159.  MOV BYTE PTR BADKEY,0 ;CLEAR BAD KEY FLAG
  160.  
  161. ;HERE WE ENCRYPT THE DATA IF IT WAS A WRITE
  162.  CMP BYTE PTR RQTYPE,3 ;IS IT WRITE?
  163.  JNE NOENCRYPT ;IF NOT, DON'T ENCRYPT
  164.  MOV BYTE PTR ENCRYPT,1 ;SET ENCRYPT MODE
  165.  CALL CRYPTIT ;ENCRYPT THE DATA
  166.  CMP BYTE PTR BADKEY,1
  167.  JE BACKFROMBIOS ;SKIP WRITE IF BAD KEY/NOT LOGGED IN
  168.  
  169. ;HERE WE DO THE ACTUAL DISK OPERATION
  170. NOENCRYPT:
  171.  PUSHF
  172.  PUSH CS
  173.  MOV AX,OFFSET BACKFROMBIOS
  174.  PUSH AX ;HERE WE ARE FAKING AN INT
  175.  MOV AH,BYTE PTR RQTYPE
  176.  MOV AL,BYTE PTR NUMSEC
  177.  MOV CX,WORD PTR CALLCX
  178.  MOV DH,BYTE PTR STHD
  179.  MOV DL,BYTE PTR DRIVE
  180.  MOV ES,WORD PTR BUFSG
  181.  MOV BX,WORD PTR BUFOS
  182.  JMP INT_JOUT ;GO TO BIOS
  183. BACKFROMBIOS:
  184.  PUSHF
  185.  PUSH AX
  186.  
  187. ;HERE WE DECRYPT THE DATA
  188.  MOV BYTE PTR ENCRYPT,0 ;SET DECRYPT MODE
  189.  CALL CRYPTIT ;DECRYPT THE DATA
  190.  
  191. ;HERE WE RETURN TO THE CALLING PROGRAM
  192.  POP AX ;INT RETURN CODE
  193.  POP BX ;FLAGS
  194.  
  195.  CMP BYTE PTR BADKEY,1 ;RETURN FAKE ERROR?
  196.  JNE NOERRRET
  197.  OR BL,1      ;SET CARRY IF KEY BAD
  198.  MOV AH,80h   ;SIMULATE NO DISK PRESENT ERROR
  199.  
  200. NOERRRET:
  201.  MOV ES,WORD PTR STKSEG
  202.  MOV SI,WORD PTR STKOFS
  203.  MOV ES:[SI+4],BX ;PUT NEW FLAGS WHERE IRET WILL RECALL THEM
  204.  
  205. RETPROG:
  206.  POP ES
  207.  POP DS
  208.  POP BP
  209.  POP DI
  210.  POP SI
  211.  POP DX
  212.  POP CX
  213.  POP BX
  214.  CLI
  215.  MOV SS,WORD PTR CS:STKSEG
  216.  MOV SP,WORD PTR CS:STKOFS ;RESTORE USER STACK
  217.  STI
  218.  IRET ;RETURN TO PROGRAM, LOADING MODIFIED FLAGS
  219.  
  220. NOPROC: ;REQUESTS NOT PROCESSED JUMP HERE
  221.  POP ES
  222.  POP DS
  223.  POP BP
  224.  POP DI
  225.  POP SI
  226.  POP DX
  227.  POP CX
  228.  POP BX
  229.  POP AX
  230.  CLI
  231.  MOV SS,WORD PTR CS:STKSEG
  232.  MOV SP,WORD PTR CS:STKOFS ;RESTORE USER STACK
  233.  STI
  234.  
  235. INT_JOUT:
  236.  DB 0EAh,00,00,00,00 ;JMP FAR
  237.  
  238. CRYPTIT: ;THIS ENCRYPTS OR DECRYPTS THE BUFFER
  239.  MOV AL,BYTE PTR NUMSEC
  240.  MOV BYTE PTR SECLFT,AL ;LOAD SECTOR COUNTER
  241.  MOV AX,WORD PTR STCYL
  242.  MOV WORD PTR CURCYL,AX ;LOAD CURRENT CYLINDER
  243.  MOV AL,BYTE PTR STHD
  244.  MOV BYTE PTR CURHD,AL    ;LOAD CURRENT HEAD
  245.  MOV AL,BYTE PTR STSEC
  246.  MOV BYTE PTR CURSEC,AL ;LOAD CURRENT SECTOR
  247.  MOV AX,WORD PTR BUFOS
  248.  MOV WORD PTR BUFPS,AX    ;LOAD BUFFER POINTER
  249.  
  250. CRYPTLOOP:
  251.  CMP BYTE PTR SECLFT,0
  252.  JE DONECRYPT ;CHECK FOR LAST SECTOR
  253.  
  254.  MOV AX,WORD PTR CURCYL
  255.  CMP AX,[BP].FIRSTCYL
  256.  JB DONTCRYPTSEC
  257.  JNE NOTBOOTSEC
  258.  
  259.  MOV AL,BYTE PTR CURHD
  260.  CMP AL,[BP].FIRSTHD
  261.  JB DONTCRYPTSEC
  262.  JNE NOTBOOTSEC
  263.  
  264.  MOV AL,BYTE PTR CURSEC
  265.  CMP AL,[BP].FIRSTSEC
  266. ;DO WE NEED A JB HERE?
  267.  JNE NOTBOOTSEC
  268.  
  269.  CALL LOADBS ;LOAD DATA FROM BOOT SECTOR
  270.  JMP DONTCRYPTSEC
  271.  
  272. NOTBOOTSEC:
  273.  MOV AX,WORD PTR CURCYL
  274.  CMP AX,[BP].LASTCYL
  275.  JA DONTCRYPTSEC
  276.  
  277.  CMP [BP].ACTIVE,1
  278.  JE DOCRYPTSEC      ;CHECK ACTIVE FLAG
  279.  CMP BYTE PTR DRIVE,1
  280.  JBE DONTCRYPTSEC
  281.  MOV BYTE PTR BADKEY,1
  282.  JMP DONTCRYPTSEC
  283. DOCRYPTSEC:
  284.  CALL CRYPTSEC ;ENCRYPT CURRENT SECTOR
  285. DONTCRYPTSEC:
  286.  CALL NEXTSEC  ;GO ON TO NEXT SECTOR
  287.  JMP CRYPTLOOP       ;LOOP
  288. DONECRYPT: RET
  289.  
  290. CRYPTSEC: ;HERE WE CRYPT ONE SECTOR
  291. ;SET UP IV
  292.  MOV AX,WORD PTR CURCYL
  293.  MOV WORD PTR IV,AX
  294.  MOV AL,BYTE PTR CURHD
  295.  MOV BYTE PTR IV+2,AL
  296.  MOV AL,BYTE PTR CURSEC
  297.  MOV BYTE PTR IV+3,AL
  298.  MOV AX,[BP].SERIAL
  299.  MOV WORD PTR IV+4,AX
  300.  MOV AX,[BP].SERIAL+2
  301.  MOV WORD PTR IV+6,AX ;SET UP IV
  302.  
  303. ;PRE-ENCRYPT IV
  304.  MOV AX,1  ;ACTUALLY ZERO BLOCKS, WILL JUST PRE-ENCRYPT IV
  305.  PUSH AX   ;STORE NUMBER OF BLOCKS
  306.  SUB SP,8 ;PRETEND TO PUSH PLAINTEXT/CIPHERTEXT ADDRESSES
  307.  MOV AX,WORD PTR KEY
  308.  PUSH CS
  309.  PUSH AX
  310.  MOV AX,OFFSET IV
  311.  PUSH CS
  312.  PUSH AX
  313.  PUSH AX ;MAKE IT LOOK LIKE A FAR CALL FOR IDEACFB
  314.  CALL _IDEACFB
  315.  ADD SP,20 ;REMOVE EXTRA WORD
  316.  
  317. ;ENCRYPT/DECRYPT THE BLOCK
  318.  MOV AX,[BP].SECSIZE
  319.  MOV CL,3
  320.  SHR AX,CL ;SECSIZE/8
  321.  INC AX    ;ONE BLOCK (IV) NOT USED
  322.  PUSH AX   ;STORE NUMBER OF BLOCKS
  323.  MOV AX,WORD PTR BUFSG
  324.  MOV BX,WORD PTR BUFPS
  325.  PUSH AX
  326.  PUSH BX
  327.  PUSH AX
  328.  PUSH BX
  329.  MOV AX,WORD PTR KEY
  330.  PUSH CS
  331.  PUSH AX
  332.  MOV AX,OFFSET IV
  333.  PUSH CS
  334.  PUSH AX
  335.  PUSH AX ;MAKE IT LOOK LIKE A FAR CALL FOR IDEACFB
  336.  CMP BYTE PTR ENCRYPT,1
  337.  JNE DECRYPT
  338.  CALL _IDEACFB
  339.  JMP DONE_CRYPTSEC
  340. DECRYPT:
  341.  CALL _IDEACFBX
  342. DONE_CRYPTSEC:
  343. ; ADD SP,18
  344.  ADD SP,20 ;REMOVE EXTRA WORD
  345.  RET
  346.  
  347. NEXTSEC: ;INCREMENT HEAD, SECTOR, CYLINDER AS NEEDED TO GO TO NEXT SECTOR
  348.  MOV AX,[BP].SECSIZE
  349.  ADD WORD PTR BUFPS,AX ;GO TO NEXT BLOCK IN MEMORY
  350.  DEC BYTE PTR SECLFT   ;COUNT DOWN SECTORS LEFT
  351.  INC BYTE PTR CURSEC   ;INCREMENT SECTOR
  352.  MOV AL,BYTE PTR CURSEC
  353.  CMP AL,[BP].MAXSEC
  354.  JBE DONE_COUNT
  355.  MOV BYTE PTR CURSEC,1 ;RESET SECTOR
  356.  INC BYTE PTR CURHD    ;INCREMENT HEAD
  357.  MOV AL,BYTE PTR CURHD
  358.  CMP AL,[BP].MAXHD
  359.  JB DONE_COUNT
  360.  MOV BYTE PTR CURHD,0  ;RESET HEAD
  361.  INC WORD PTR CURCYL   ;THEN INCREMENT CYLINDER
  362. DONE_COUNT: RET
  363.  
  364. LOADBS:
  365.  CMP BYTE PTR DRIVE,1
  366.  JA IGNOREBS ;DON'T ALTER PARAMS FOR HARD DRIVE
  367.  MOV [BP].ACTIVE,0 ;DEFAULT OFF
  368.  MOV ES,WORD PTR BUFSG
  369.  MOV SI,WORD PTR BUFPS ;GET ACCESS TO BUFFER
  370.  CMP WORD PTR ES:[SI+510],0AA55h ;CHECK FOR BOOT-RECORD SIGNATURE
  371.  JNE IGNOREBS ;BAILOUT IF BOOT SECTOR LOOKS BAD
  372.  CMP WORD PTR ES:[SI+3],'RC'
  373.  JNE NOTCRYPT
  374.  CMP WORD PTR ES:[SI+5],'PY'
  375.  JNE NOTCRYPT
  376.  MOV AX,WORD PTR FKEYCHK
  377.  CMP WORD PTR ES:[SI+7],AX
  378.  JNE NOTGOODKEY
  379.  MOV AX,WORD PTR FKEYCHK+2
  380.  CMP WORD PTR ES:[SI+9],AX
  381.  JNE NOTGOODKEY
  382.  JMP GOODKEY
  383. NOTGOODKEY:
  384.  MOV BYTE PTR BADKEY,1
  385.  JMP NOTCRYPT
  386. GOODKEY:
  387.  MOV [BP].ACTIVE,1 ;TURN ON ENCRYPTION
  388. NOTCRYPT:
  389.  MOV AL,ES:[SI+18h]
  390.  MOV [BP].MAXSEC,AL ;STORE MAX SECTOR
  391.  MOV AL,ES:[SI+1Ah]
  392.  MOV [BP].MAXHD,AL  ;STORE MAX HEAD
  393.  MOV AX,ES:[SI+0Bh]
  394.  MOV [BP].SECSIZE,AX ;STORE BYTES PER SECTOR
  395.  MOV AX,ES:[SI+27h]
  396.  MOV [BP].SERIAL,AX  ;STORE FIRST WORD OF SERIAL NUMBER
  397.  MOV AX,ES:[SI+29h]
  398.  MOV [BP].SERIAL+2,AX ;STORE SECOND WORD OF SERIAL NUMBER
  399. IGNOREBS:
  400.  RET
  401.  
  402. ;VARIABLES HERE WILL BE LOADED BY LOGIN
  403.     ALIGN 4
  404. LOADDATA:
  405. TSRVER    DB '130A'            ;VERSION FOR CHECK
  406. REALBIOS LABEL DWORD
  407.     DW 0,0
  408. FKEYCHK:DW 2 DUP (0ffffh)
  409. FKEY:    DB 13,10,'Secure Drive Version 1.3A',13,10
  410.     DB 'TSR Installed',13,10,'$'
  411. ALRINS: DB 13,10,'Secure Drive TSR already resident',13,10,'$'
  412.     DB (104-($-FKEY)) DUP (0aah)      ;FLOPPY ENCRYPTION KEY
  413. FKEYV10 DB 0
  414.     DB "PPP"              ;PAD FOR ALIGNMENT
  415. HKEYCHK:DW 2 DUP (0ffffh)
  416. HKEY    LABEL BYTE
  417.     DB 104 DUP (0bbh)          ;HARD DRIVE ENCRYPTION KEY
  418. HKEYV10 DB 0
  419.     DB "PPP"              ;PAD FOR ALIGNMENT
  420. FDA:    DISKDATA <0,'A',0,0,1,0FFFFh,18,2,512,0,0,0,'P'>
  421. FDB:    DISKDATA <0,'B',0,0,1,0FFFFh,18,2,512,0,0,0,'P'>
  422. HD1:    DISKDATA <0,'Z',0FFFFh,0,0,0,0,0,512,0,0,0,'P'>
  423. HD2    LABEL BYTE
  424.     REPT MAXDRV-1
  425.     DISKDATA <0,'Z',0FFFFh,0,0,0,0,0,512,0,0,0,'P'>
  426.     ENDM
  427.  
  428.     ALIGN 4
  429. ;VARIABLES HERE STAY PUT
  430. STKSEG: DW ? ;SEGMENT OF USER STACK
  431. STKOFS: DW ? ;OFFSET OF USER STACK
  432.  
  433. RQTYPE: DB ? ;REQUEST TYPE, AH FROM CALL
  434. DRIVE:    DB ? ;DRIVE FROM CALL
  435. NUMSEC: DB ? ;NUMBER OF SECTORS TO READ (AL FROM CALL)
  436. SECLFT: DB ? ;NUMBER OF SECTORS LEFT TO PROCESS
  437. CALLCX: DW ? ;ORIGINAL CX
  438. KEY:    DW ? ;CURRENTLY SELECTED KEY
  439. BADKEY: DB ? ;KEY BAD FLAG
  440.  
  441. STCYL:    DW ? ;START CYLINDER FROM CALL
  442. CURCYL: DW ? ;CURRENT CYLINDER BEING PROCESSED
  443.  
  444. STSEC:    DB ? ;START SECTOR FROM CALL
  445. CURSEC: DB ? ;CURRENT SECTOR BEING PROCESSED
  446.  
  447. STHD:    DB ? ;START HEAD FROM CALL
  448. CURHD:    DB ? ;CURRENT HEAD BEING PROCESSED
  449.  
  450. BUFOS:    DW ? ;OFFSET OF TARGET BUFFER
  451. BUFPS:    DW ? ;CURRENT POSITION WITHIN BUFFER
  452. BUFSG:    DW ? ;SEGMENT OF TARGET BUFFER
  453.  
  454. ENCRYPT: DB ? ;1 FOR ENCRYPT, 0 FOR DECRYPT
  455. IV:  DB 8 DUP (?)   ;IV FOR CFB
  456.  
  457. ; Copyright (c) 1993 Colin Plumb.  This code may be freely
  458. ; distributed under the terms of the GNU General Public Licence.
  459.  
  460. ; A core operation in IDEA is multiplication modulo 65537.
  461. ; The valid inputs, 1 through 66636 inclusive are represented in
  462. ; 16-bit registers modulo 65536.  I.e. a value of 0 means 65536,
  463. ; or -1.  Thus, we need to test for that specially.  -x, modulo
  464. ; 65537, is 65537-x = 1-x.
  465. ; For any other number, represent the product as a*65536+b.  Since
  466. ; 65536 = -1 (mod 65537), this is the same number as b-a.  Should
  467. ; this result be negautive (generate a borrow), -n mod 65537 = 1-n
  468. ; mod 65536.  Or in other words, if you add the borrow bit back on,
  469. ; you get the right answer.
  470.  
  471. ; This is what the assembly code does.    It forms a zero, and adds
  472. ; that on with carry.
  473.  
  474. ; Another useful optimisation takes advantage of the fact that
  475. ; a and b are equal only if the answer is congruent to 0 mod 65537.
  476. ; Since 65537 is prime, this happens only if one of the inputs is
  477. ; congruent to 0 mod 65537.  Since the inputs are all less than 65537,
  478. ; this means it must have been zero.
  479.  
  480. ; The code below tests for a zero result of the subtraction, and if
  481. ; one arises, it branches out of line to figure out what happened.
  482.  
  483.  
  484. ; This code implemets the IDEA encryption algorithm.
  485. ; It follows in pseudo-C, where the * operator operates
  486. ; modulo 65537, as Idea needs.    (If you don't understand,
  487. ; learn IDEA better.)
  488.  
  489. ; IDEA is works on 16-bit units.  If you're processing bytes,
  490. ; it's defined to be big-endian, so an Intel machine needs to
  491. ; swap the bytes around.
  492.  
  493. ; void Idea(u_int16 *in, u_int16 *out, u_int16 *key)
  494. ; {
  495. ;     register u+int16 x0, x1, x2, x3, s1, s2, round;
  496. ;
  497. ;     x0 = *in++;  x1 = *in++;  x2 = *in++;    x3 = *in;
  498. ;
  499. ;     for (round = 0; round < 8; round++) {
  500. ;         x0 *= *key++;
  501. ;         x1 += *key++;
  502. ;         x2 += *key++;
  503. ;         x3 *= *key++;
  504. ;
  505. ;         s1  = x1;  s2    = x2;
  506. ;         x2 ^= x0;  x1 ^= x3;
  507. ;
  508. ;         x2 *= *key++;
  509. ;         x1 += x2;
  510. ;         x1 *= *key++;
  511. ;         x2 += x1;
  512. ;
  513. ;         x0 ^= x1;  x3 ^= x2;
  514. ;         x1 ^= s2;  x2 ^= s1;
  515. ;     }
  516. ;     *out++ = x0 * *key++;
  517. ;     *out++ = x2 + *key++;          /* Yes, this is x2, not x1 */
  518. ;     *out++ = x1 + *key++;
  519. ;     *out    = x3 * *key;
  520. ; }
  521.  
  522. ; ds:si points to key, ax, dx are temps, args in bx, cx, di, bp
  523. ; Trashes *all* registers.  direction flag must be clear.
  524. ; Leaves es zero.
  525.  
  526. ; Since there is no spare register to hold the loop count, I make
  527. ; clever use of the stack, pushing the start of the loop several
  528. ; times and using a ret instruction to do the return.
  529.  
  530. ; Annoyingly, lods is fastest on 8086's, but other techniques are
  531. ; best on 386's.  Well, that's what the manual says, but real
  532. ; life is different.  USELODS wins on a 386SX, at least.
  533. ; Leave it set for all platforms.
  534.  
  535. USELODS        equ      1
  536.  
  537. ; bp must be x0 for some of the code below to work
  538. x0      equ         bp
  539. x1      equ         bx
  540. x2      equ         cx
  541. x3      equ         di
  542. ; di must be x3 for some of the code below to work
  543.  
  544. ;; Now, this is rather interesting.  We test for zero arguments
  545. ;; after the multiply.    Assuming random inputs, one or both are
  546. ;; zero (2^17-1)/2^32, or approximately 1/32786 of the time.
  547. ;; Encryption in any feedback mode produces essentially random
  548. ;; inputs, so average-case analysis is okay.  While we don't
  549. ;; want the out-of-line code to waste time, it is not worth
  550. ;; slowing down the in-line case to speed it up.
  551. ;;
  552. ;; Basically, we start inverting the source x, and if that was 0,
  553. ;; we use the inverse of the key instead.
  554.  
  555. Core1Z:
  556.     neg       x0
  557.     jnz       Core1Za
  558. if USELODS
  559.     sub       x0,[si-2]
  560. else
  561.     sub       x0,[si]
  562. endif
  563. Core1Za:
  564.     inc       x0
  565.     jmp       Core1done
  566. Core2Z:
  567.     neg       x3
  568.     jnz       Core2Za
  569. if USELODS
  570.     sub       x3,[si-2]
  571. else
  572.     sub       x3,[si+6]
  573. endif
  574. Core2Za:
  575.     inc       x3
  576.     jmp       Core2done
  577. Core3Z:
  578.     neg       x2
  579.     jnz       Core3Za
  580. if USELODS
  581.     sub       x2,[si-2]
  582. else
  583.     sub       x2,[si+8]
  584. endif
  585. Core3Za:
  586.     inc       x2
  587.     jmp       Core3done
  588. Core4Z:
  589.     neg       x1
  590.     jnz       Core4Za
  591. if USELODS
  592.     sub       x1,[si-2]
  593. else
  594.     sub       x1,[si+10]
  595. endif
  596. Core4Za:
  597.     inc       x1
  598.     jmp       Core4done
  599.  
  600. ; We need a constant 0 that we can move into a register without affecting
  601. ; the carry flag (as the classic xor ax,ax is wont to do), so we use the
  602. ; es register for a constant 0 source.    This is okay even in protected
  603. ; mode.  (I *told* you this was tricky code!)
  604.  
  605. ; BTW, since you wanted to know, this is 8 + 78*4 + 16 = 336 instructions.
  606.  
  607. Core        proc    near
  608.     xor       ax,ax
  609.     mov       es,ax
  610.     mov       ax,OFFSET Finish
  611.     push        ax
  612.     mov       ax,OFFSET Coreloop
  613.     push        ax          ; Loop 3 times, then return
  614.     push        ax
  615.     push        ax
  616.  
  617. Coreloop:
  618. if USELODS
  619.     lodsw
  620. else
  621.     mov       ax,[si]          ; x0 *= *key++
  622. endif
  623.     mul       x0
  624.     sub       ax,dx
  625.     jz      Core1Z
  626.     mov       x0,es
  627.     adc       x0,ax
  628. Core1done:
  629.  
  630. if USELODS
  631.     lodsw
  632.     add       x1,ax
  633.     lodsw
  634.     add       x2,ax
  635. else
  636.     add       x1,[si+2]        ; x1 += *key++
  637.     add       x2,[si+4]        ; x2 += *key++
  638. endif
  639.  
  640. if USELODS
  641.     lodsw
  642. else
  643.     mov       ax,[si+6]        ; x3 += *key++
  644. endif
  645.     mul       x3
  646.     sub       ax,dx
  647.     jz      Core2Z
  648.     mov       x3,es
  649.     adc       x3,ax
  650. Core2done:
  651.  
  652.     push        x1            ; s1 = x1
  653.     push        x2              ; s2 = x2
  654.  
  655.     xor       x1,x3        ; x1 ^= x3
  656.     xor       x2,x0        ; x2 ^= x0
  657.  
  658. if USELODS
  659.     lodsw
  660. else
  661.     mov       ax,[si+8]        ; x2 *= *key++
  662. endif
  663.     mul       x2
  664.     sub       ax,dx
  665.     jz      Core3Z
  666.     mov       x2,es
  667.     adc       x2,ax
  668. Core3done:
  669.  
  670.     add       x1,x2        ; x1 += x2
  671.  
  672. if USELODS
  673.     lodsw
  674. else
  675.     mov       ax,[si+10]         ; x1 *= *key++
  676. endif
  677.     mul       x1
  678.     sub       ax,dx
  679.     jz      Core4Z
  680.     mov       x1,es
  681.     adc       x1,ax
  682. Core4done:
  683.  
  684.     add       x2,x1        ; x2 += x1
  685.  
  686.     xor       x0,x1        ; x0 ^= x1
  687.     xor       x3,x2        ; x3 ^= x2
  688.  
  689.     pop       dx
  690.     xor       x1,dx        ; x1 ^= s2
  691.     pop       dx
  692.     xor       x2,dx        ; x2 ^= s1
  693.  
  694. ; Second unrolling of loop
  695. if USELODS
  696.     lodsw
  697. else
  698.     mov    ax,[si+12]        ; x0 *= *key++
  699. endif
  700.     mul       x0
  701.     sub       ax,dx
  702.     jz      Core5Z
  703.     mov       x0,es
  704.     adc       x0,ax
  705. Core5done:
  706.  
  707. if USELODS
  708.     lodsw
  709.     add       x1,ax
  710.     lodsw
  711.     add       x2,ax
  712. else
  713.     add       x1,[si+14]         ; x1 += *key++
  714.     add       x2,[si+16]         ; x2 += *key++
  715. endif
  716.  
  717. if USELODS
  718.     lodsw
  719. else
  720.     mov       ax,[si+18]         ; x3 *= *key++
  721. endif
  722.     mul       x3
  723.     sub       ax,dx
  724.     jz      Core6Z
  725.     mov       x3,es
  726.     adc       x3,ax
  727. Core6done:
  728.  
  729.     push        x1             ; s1 = x1
  730.     push        x2              ; s2 = x2
  731.  
  732.     xor       x1,x3        ; x1 ^= x3
  733.     xor       x2,x0        ; x2 ^= x0
  734.  
  735. if USELODS
  736.     lodsw
  737. else
  738.     mov       ax,[si+20]         ; x2 *= *key++
  739. endif
  740.     mul       x2
  741.     sub       ax,dx
  742.     jz      Core7Z
  743.     mov       x2,es
  744.     adc       x2,ax
  745. Core7done:
  746.  
  747.     add       x1,x2        ; x1 += x2
  748.  
  749. if USELODS
  750.     lodsw
  751. else
  752.     mov       ax,[si+22]         ; x1 *= *key++
  753. endif
  754.     mul       x1
  755.     sub       ax,dx
  756.     jz      Core8Z
  757.     mov       x1,es
  758.     adc       x1,ax
  759. Core8done:
  760.  
  761.     add       x2,x1        ; x2 += x1
  762.  
  763.     xor       x0,x1        ; x0 ^= x1
  764.     xor       x3,x2        ; x3 ^= x2
  765.  
  766.     pop       dx
  767.     xor       x1,dx        ; x1 ^= s2
  768.     pop       dx
  769.     xor       x2,dx        ; x2 ^= s1
  770.  
  771. ife USELODS
  772.     lea       si,[si+24]
  773. endif
  774.  
  775.     ret       ; Used as a loop instruction!
  776.  
  777. Core5Z:
  778.     neg       x0
  779.     jnz       Core5Za
  780. if USELODS
  781.     sub       x0,[si-2]
  782. else
  783.     sub       x0,[si+12]
  784. endif
  785. Core5Za:
  786.     inc       x0
  787.     jmp       Core5done
  788. Core6Z:
  789.     neg       x3
  790.     jnz       Core6Za
  791. if USELODS
  792.     sub       x3,[si-2]
  793. else
  794.     sub       x3,[si+18]
  795. endif
  796. Core6Za:
  797.     inc       x3
  798.     jmp       Core6done
  799. Core7Z:
  800.     neg       x2
  801.     jnz       Core7Za
  802. if USELODS
  803.     sub       x2,[si-2]
  804. else
  805.     sub       x2,[si+20]
  806. endif
  807. Core7Za:
  808.     inc       x2
  809.     jmp       Core7done
  810. Core8Z:
  811.     neg       x1
  812.     jnz       Core8Za
  813. if USELODS
  814.     sub       x1,[si-2]
  815. else
  816.     sub       x1,[si+22]
  817. endif
  818. Core8Za:
  819.     inc       x1
  820.     jmp       Core8done
  821. Core9Z:
  822.     neg       x0
  823.     jnz       Core9Za
  824. if USELODS
  825.     sub       x0,[si-2]
  826. else
  827.     sub       x0,[si]
  828. endif
  829. Core9Za:
  830.     inc       x0
  831.     jmp       Core9done
  832. ; Special: compute into dx (zero on entry)
  833. Core10Z:
  834.     sub       dx,x3
  835.     jnz       Core10Za
  836. if USELODS
  837.     sub       dx,[si-2]
  838. else
  839.     sub       dx,[si+6]
  840. endif
  841. Core10Za:
  842.     inc       dx
  843. ;     jmp        Core10done
  844.     ret
  845.  
  846.  
  847. Finish:
  848. if USELODS
  849.     lodsw
  850. else
  851.     mov       ax,[si]          ; x0 *= *key++
  852. endif
  853.     mul       x0
  854.     sub       ax,dx
  855.     jz      Core9Z
  856.     mov       x0,es
  857.     adc       x0,ax
  858. Core9done:
  859.  
  860.     xchg        x1,x2
  861. if USELODS
  862.     lodsw
  863.     add       x1,ax
  864.     lodsw
  865.     add       x2,ax
  866. else
  867.     add       x1,[si+2]        ; x1 += *key++
  868.     add       x2,[si+4]       ; x2 += *key++
  869. endif
  870.  
  871. ; This is special: compute into dx, not x3
  872. if USELODS
  873.     lodsw
  874. else
  875.     mov       ax,[si+6]        ; x3 *= *key++
  876. endif
  877.     mul       x3
  878.     sub       ax,dx
  879.     mov       dx,es
  880.     jz      Core10Z
  881.     adc       dx,ax
  882. Core10done:
  883.  
  884.     ret
  885.  
  886.     endp
  887.  
  888. ; Okay, the basic plan for the CFB kernel is
  889. ; get x0,x1,x2,x3
  890. ; get key pointer
  891. ; call core
  892. ; get buffer pointers
  893. ;Loop:
  894. ; lodsw
  895. ; xor         ax,x0
  896. ; mov    x0,ax
  897. ; stosw
  898. ; lodsw
  899. ; xor         ax,x1
  900. ; mov         x0,ax
  901. ; stosw
  902. ; lodsw
  903. ; xor         ax,x2
  904. ; mov         x0,ax
  905. ; stosw
  906. ; lodsw
  907. ; xor         ax,x3
  908. ; mov         x3,ax
  909. ; stosw
  910. ; push buffer pointers
  911. ; get key pointer
  912. ; call          core
  913. ; pop buffer pointers
  914. ; loop
  915. ; lodsw/xor/etc.
  916. ;
  917. ;
  918. ; This function is designed to go in the middle of a byte-granularity
  919. ; CFB engine.  It performs "len" encryptions of the IV, encrypting
  920. ; 8*(len-1) bytes from the source to the destination.  The idea is
  921. ; that you first xor any odd leading bytes, then call this function,
  922. ; then xor up to 8 trailing bytes.
  923.  
  924. ; The main loop in this is 38 instructions, plus the 336 for the core
  925. ; makes 374 total.  That's 46.75 instructions per byte.
  926. ; (It's the same for IdeaCFBx)
  927.  
  928. ; IV, key, plain, cipher, len
  929. ;     public        _IdeaCFB
  930. ;_IdeaCFB proc far     ; Args are at [sp+4]
  931. _IDEACFB:
  932.     cld
  933.     push        bp
  934.     push        si
  935.     push        di
  936.     push        ds          ; 8 more words here, so args are at [sp+12]
  937. ; To be precise, IV is at 12, key at 16, plain at 20,
  938. ; cipher at 24 and len at 28
  939.     mov       bp,sp
  940.     lds       si,[bp+12]         ; IV
  941. ; Load and byte-swap IV
  942.     mov       ax,[si]
  943.     xchg        ah,al
  944.     mov       x1,[si+2]
  945.     mov       x2,[si+4]
  946.     xchg        bh,bl
  947.     xchg        ch,cl
  948.     mov       dx,[si+6]
  949.     xchg        dh,dl
  950.  
  951.     lds       si,[bp+16]         ; Key
  952.     mov       x0,ax
  953.     mov       x3,dx
  954.  
  955.     call        Core
  956. IdeaCFBLoop:
  957. ;     mov        ax,x0
  958. ;     mov        bp,sp
  959. ;     dec        WORD PTR [bp+28]        ; Decrement count
  960. ;     jz       IdeaCFBEnd
  961. ;     lds        si,[bp+20]
  962. ;     les        di,[bp+24]
  963. ;     mov        x0,ax
  964. ; Alternate code: (which is faster?  Two moves or three segment overrides?)
  965.     mov       si,sp
  966.     dec       WORD PTR ss:[si+28]
  967.     jz      IdeaCFBEnd
  968.     les       di,ss:[si+24]
  969.     lds       si,ss:[si+20]
  970.  
  971.     lodsw
  972.     xchg        ah,al
  973.     xor       ax,x0
  974.     mov       x0,ax
  975.     xchg        ah,al
  976.     stosw
  977.     lodsw
  978.     xchg        ah,al
  979.     xor       ax,x1
  980.     mov       x1,ax
  981.     xchg        ah,al
  982.     stosw
  983.     lodsw
  984.     xchg        ah,al
  985.     xor       ax,x2
  986.     mov       x2,ax
  987.     xchg        ah,al
  988.     stosw
  989.     lodsw
  990.     xchg        ah,al
  991.     xor       ax,dx
  992.     mov       dx,ax
  993.     xchg        ah,al
  994.     stosw
  995.  
  996. ;     mov        ax,x0
  997. ;     mov        bp,sp
  998. ;     mov        [bp+20],si          ; Save source offset
  999. ;     mov        [bp+24],di          ; Save destination offset
  1000. ;     lds        si,[bp+16]          ; Key
  1001. ;     mov        x0,ax         ; Get x0 in place for another iteration
  1002. ; Alternate code for the above: (which is faster?  One move or three ss:?)
  1003.     mov       ax,si
  1004.     mov       si,sp
  1005.     mov       ss:[si+20],ax
  1006.     mov       ss:[si+24],di
  1007.     lds       si,ss:[si+16]
  1008.  
  1009.     mov       x3,dx        ; Get x3 in place
  1010.     mov       ax,OFFSET IdeaCFBLoop
  1011.     push        ax
  1012.     jmp       Core
  1013.  
  1014. IdeaCFBEnd:
  1015. ;     lds        si,[bp+12]
  1016.     lds       di,ss:[si+12]    ; Get IV for writing back
  1017.  
  1018.     mov       ax,x0
  1019.     xchg        ah,al
  1020.     mov       [di],ax          ; Use stosw?
  1021.     xchg        bh,bl
  1022.     xchg        ch,cl
  1023.     mov       [di+2],x1
  1024.     mov       [di+4],x2
  1025.     xchg        dh,dl
  1026.     mov       [di+6],dx
  1027.  
  1028.     pop       ds
  1029.     pop       di
  1030.     pop       si
  1031.     pop       bp
  1032.  
  1033.     ret
  1034.  
  1035.     endp
  1036.  
  1037. ; This decoding step is similar, except that instead of
  1038. ;     lods
  1039. ;     xor        x0,ax
  1040. ;     mov        ax,x0
  1041. ;      stos
  1042. ; the feedback step is
  1043. ;     lods
  1044. ;     xchg         x0,ax
  1045. ;     xor        ax,x0
  1046. ;     stos
  1047.  
  1048. ; IV, key, cipher, plain, len
  1049. ;     public        _IdeaCFBx
  1050. ;_IdeaCFBx proc far      ; Args are at [sp+4]
  1051. _IDEACFBX:
  1052.     cld
  1053.     push        bp
  1054.     push        si
  1055.     push        di
  1056.     push        ds          ; 8 more words here, so args are at [sp+12]
  1057.     mov       bp,sp
  1058.     lds       si,[bp+12]         ; IV
  1059. ; Load and byte-swap IV
  1060.     mov       ax,[si]
  1061.     xchg        ah,al
  1062.     mov       x1,[si+2]
  1063.     mov       x2,[si+4]
  1064.     xchg        bh,bl
  1065.     xchg        ch,cl
  1066.     mov       dx,[si+6]
  1067.     xchg        dh,dl
  1068.  
  1069.     lds       si,[bp+16]         ; Key
  1070.     mov       x0,ax
  1071.     mov       x3,dx
  1072.  
  1073.     call        Core
  1074. IdeaCFBxLoop:
  1075. ;     mov        ax,x0
  1076. ;     mov        bp,sp
  1077. ;     dec        WORD PTR [bp+28]        ; Decrement count
  1078. ;     jz       IdeaCFBxEnd
  1079. ;     lds        si,[bp+20]
  1080. ;     les        di,[bp+24]
  1081. ;     mov        x0,ax
  1082. ; Alternate code: (which is faster?  Two moves or three segment overrides)
  1083.     mov       si,sp
  1084.     dec       WORD PTR ss:[si+28]
  1085.     jz      IdeaCFBxEnd
  1086.     les       di,ss:[si+24]
  1087.     lds       si,ss:[si+20]
  1088.  
  1089.     lodsw
  1090.     xchg        ah,al
  1091.     xchg        x0,ax
  1092.     xor       ax,x0
  1093.     xchg        ah,al
  1094.     stosw
  1095.     lodsw
  1096.     xchg        ah,al
  1097.     xchg        x1,ax
  1098.     xor       ax,x1
  1099.     xchg        ah,al
  1100.     stosw
  1101.     lodsw
  1102.     xchg        ah,al
  1103.     xchg        x2,ax
  1104.     xor       ax,x2
  1105.     xchg        ah,al
  1106.     stosw
  1107.     lodsw
  1108.     xchg        ah,al
  1109.     xchg        dx,ax
  1110.     xor       ax,dx
  1111.     xchg        ah,al
  1112.     stosw
  1113.  
  1114. ;     mov        ax,x0
  1115. ;     mov        bp,sp
  1116. ;     mov        [bp+20],si          ; Save source offset
  1117. ;     mov        [bp+24],di          ; Save destination offset
  1118. ;     lds        si,[bp+16]          ; Key
  1119. ;     mov        x0,ax         ; Get x0 in place for another iteration
  1120. ; Alternate code for the above: (which is faster?  One move or three ss:?)
  1121.     mov       ax,si
  1122.     mov       si,sp
  1123.     mov       ss:[si+20],ax
  1124.     mov       ss:[si+24],di
  1125.     lds       si,ss:[si+16]
  1126.  
  1127.     mov       x3,dx        ; Get x3 in place
  1128.     mov       ax,OFFSET IdeaCFBxLoop
  1129.     push        ax
  1130.     jmp       Core
  1131.  
  1132. IdeaCFBxEnd:
  1133. ;     lds        si:[bp+12]
  1134.     lds       di,ss:[si+12]    ; Get IV for writing back
  1135.  
  1136.     mov       ax,x0
  1137.     xchg        ah,al
  1138.     mov       [di],ax          ; Use stosw?
  1139.     xchg        bh,bl
  1140.     xchg        ch,cl
  1141.     mov       [di+2],x1
  1142.     mov       [di+4],x2
  1143.     xchg        dh,dl
  1144.     mov       [di+6],dx
  1145.  
  1146.  
  1147.     pop       ds
  1148.     pop       di
  1149.     pop       si
  1150.     pop       bp
  1151.  
  1152.     ret
  1153.  
  1154.     endp
  1155. END_OF_FILE:
  1156. _TEXT ENDS
  1157. END START
  1158.